//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V1.0.1
#include "app_io_ctrl.h"
#include <string.h>
#include <stdio.h>

/************************************************************内部结构Start**********************************************************************/
typedef enum
{
    Lock   = 0,//上锁
    Unlock = 1,//解锁
}WHT_IO_Ctrl_Lock_enum;

typedef enum
{
    IO_Ctrl_Mode_Switch = 0,//开关模式
    IO_Ctrl_Mode_Flash  = 1,//闪烁模式
    IO_Ctrl_Mode_SOS    = 2,//SOS模式
}WHT_IO_Ctrl_Mode_enum;

typedef enum
{
    SOS_Short_Flash  = 0,//短闪
    SOS_Length_Flash = 1,//长闪
    SOS_Flash_Idle   = 2,//短长闪间隔
    SOS_Cycle_Idle   = 3,//与下次闪烁间隔
}WHT_SOS_Run_State_enum;

typedef struct
{
    WHT_IO_Ctrl_State_enum State;
}WHT_IO_Ctrl_Switch_t;//开关模式

typedef struct
{
    unsigned short Flash_Count;      //闪烁次数,0表示持续闪烁
    unsigned short ON_Task_Count;    //打开任务时间
    unsigned short New_Task_Count;   //当前执行任务时间,初始值为0
    unsigned short Cycle_Task_Count; //闪烁周期任务时间
    WHT_IO_Ctrl_State_enum End_State;//结束后状态
}WHT_IO_Ctrl_Flash_t;//闪烁模式

typedef struct
{
    unsigned short Flash_Count;      //闪烁次数,0表示持续闪烁
    unsigned short ON_Time;          //点亮时间,小于等于Flash_Cycle
    unsigned short Flash_Cycle;      //闪烁周期
    WHT_IO_Ctrl_State_enum End_State;//结束后状态
    WHT_IO_Ctrl_enum Name;
}WHT_IO_Ctrl_Flash_Config_t;

typedef struct
{
    #define SOS_Flash_Count                       3                                      //SOS国际闪烁次数
    #define SOS_Short_Flash_ON_Task_Count         (333 / (IO_Ctrl_Task_Update_Rate))     //短闪点亮时间
    #define SOS_Short_Flash_Cycle_Task_Count      (SOS_Short_Flash_ON_Task_Count * 2)    //短闪周期时间
    #define SOS_Length_Flash_ON_Task_Count        (SOS_Short_Flash_ON_Task_Count * 3)    //长闪点亮时间
    #define SOS_Length_Flash_Cycle_Task_Count     (SOS_Short_Flash_Cycle_Task_Count * 2) //长闪周期时间
    #define SOS_Flash_Idle_Task_Count             (SOS_Short_Flash_Cycle_Task_Count)     //短长闪间隔时间
    #define SOS_Cycle_Idle_Task_Count             (SOS_Short_Flash_ON_Task_Count * 7)    //周期间隔时间

    WHT_IO_Ctrl_Mode_enum Save_Current_Mode;
    WHT_SOS_Run_State_enum Run_State;
    unsigned short New_Task_Count;    //当前执行任务时间,初始值为0
    unsigned short Short_Flash_Count; //闪烁次数
    unsigned short Length_Flash_Count;//闪烁次数
}WHT_IO_Ctrl_SOS_t;//国际救援模式

typedef struct
{
    WHT_IO_Ctrl_Lock_enum Lock;  //锁后不刷新(SOS除外)
    WHT_IO_Ctrl_Mode_enum Mode;  //模式
    WHT_IO_Ctrl_Switch_t Switch; //开关
    WHT_IO_Ctrl_Flash_t Flash;   //闪烁
    WHT_IO_Ctrl_SOS_t SOS;       //SOS
}WHT_IO_Ctrl_Former_t;
/*********************************************************内部结构End*************************************************************************/
//任务句柄
static TaskHandle_t WHT_IO_Ctrl_Task_Handle = NULL;
//所有IO_Ctrl实时状态
static volatile WHT_IO_Ctrl_Former_t WHT_IO_Ctrl_Former[IO_Ctrl_Sum_Count];


static void WHT_IO_Ctrl_State_Reset(void)
{
    for (unsigned int i = 0; i < IO_Ctrl_Sum_Count; i++)
    {
        WHT_IO_Ctrl_Former[i].Lock = Lock;
        WHT_IO_Ctrl_Former[i].Mode = IO_Ctrl_Mode_Switch;
        WHT_IO_Ctrl_Former[i].SOS.Save_Current_Mode = WHT_IO_Ctrl_Former[i].Mode;
        WHT_IO_Ctrl_Former[i].Switch.State = IO_Ctrl_OFF;
    }
}
static void WHT_IO_Ctrl_Set_Switch_Value(WHT_IO_Ctrl_enum number, WHT_IO_Ctrl_State_enum state)
{
    if (WHT_IO_Ctrl_Former[number].Mode == IO_Ctrl_Mode_SOS)
    {
        return;
    }

    WHT_IO_Ctrl_Former[number].Lock = Lock;
    WHT_IO_Ctrl_Former[number].Switch.State = state;
    WHT_IO_Ctrl_Former[number].Mode = IO_Ctrl_Mode_Switch;
    WHT_IO_Ctrl_Former[number].Lock = Unlock;
}
static void WHT_IO_Ctrl_Set_Flash_Value(WHT_IO_Ctrl_enum number, const WHT_IO_Ctrl_Flash_Config_t* flash_config)
{
    if (WHT_IO_Ctrl_Former[number].Mode == IO_Ctrl_Mode_SOS)
    {
        return;
    }

    WHT_IO_Ctrl_Former[number].Lock = Lock;                                            //上锁
    WHT_IO_Ctrl_Former[number].Flash.End_State = flash_config->End_State;              //闪烁结束后的状态
    WHT_IO_Ctrl_Former[number].Flash.Flash_Count = flash_config->Flash_Count;          //闪烁的次数
    WHT_IO_Ctrl_Former[number].Flash.ON_Task_Count = flash_config->ON_Time/(IO_Ctrl_Task_Update_Rate);//点亮任务时间数
    WHT_IO_Ctrl_Former[number].Flash.Cycle_Task_Count = flash_config->Flash_Cycle/(IO_Ctrl_Task_Update_Rate); //周期点亮任务时间数
    WHT_IO_Ctrl_Former[number].Flash.New_Task_Count = 0;                               //重新计数
    WHT_IO_Ctrl_Former[number].Mode = IO_Ctrl_Mode_Flash;                              //模式更改
    WHT_IO_Ctrl_Former[number].Lock = Unlock;                                          //解锁
}
static void WHT_IO_Ctrl_Start_SOS_Config(WHT_IO_Ctrl_enum number)
{
    if (WHT_IO_Ctrl_Former[number].Mode != IO_Ctrl_Mode_SOS) //先判断，防止后面无法退出SOS模式
    {
        WHT_IO_Ctrl_Former[number].SOS.Save_Current_Mode = WHT_IO_Ctrl_Former[number].Mode;
        WHT_IO_Ctrl_Former[number].SOS.Short_Flash_Count = SOS_Flash_Count;
        WHT_IO_Ctrl_Former[number].SOS.Length_Flash_Count = SOS_Flash_Count;
        WHT_IO_Ctrl_Former[number].SOS.Run_State = SOS_Short_Flash;
        WHT_IO_Ctrl_Former[number].SOS.New_Task_Count = 0;
        WHT_IO_Ctrl_Former[number].Mode = IO_Ctrl_Mode_SOS;
    }
}
static void WHT_IO_Ctrl_End_SOS_Config(WHT_IO_Ctrl_enum number)
{
    if (WHT_IO_Ctrl_Former[number].Mode == IO_Ctrl_Mode_SOS)
    {
        WHT_IO_Ctrl_Former[number].Mode = WHT_IO_Ctrl_Former[number].SOS.Save_Current_Mode;
    }
}

/**************************************外部调用函数********************************************/
static void WHT_IO_Ctrl_Set_State(WHT_IO_Ctrl_enum name, WHT_IO_Ctrl_State_enum state)
{
    if (name == IO_Ctrl_ALL)
    {
        for (unsigned int i = 0; i < IO_Ctrl_Sum_Count; i++)
        {
            WHT_IO_Ctrl_Set_Switch_Value((WHT_IO_Ctrl_enum)i, state);
        }
    }
    else if (name < IO_Ctrl_Sum_Count)
    {
        WHT_IO_Ctrl_Set_Switch_Value(name, state);
    }

    vTaskResume(WHT_IO_Ctrl_Task_Handle);//恢复任务
}
static void WHT_IO_Ctrl_Set_Flash(WHT_IO_Ctrl_enum name, unsigned short flash_count, unsigned short on_time, unsigned short flash_cycle, WHT_IO_Ctrl_State_enum end_state)
{
    WHT_IO_Ctrl_Flash_Config_t flash_config;

    flash_config.Name        = name;
    flash_config.Flash_Count = flash_count;
    flash_config.ON_Time     = on_time;
    flash_config.Flash_Cycle = flash_cycle;
    flash_config.End_State   = end_state;

    if (name == IO_Ctrl_ALL)
    {
        for (unsigned int i = 0; i < IO_Ctrl_Sum_Count; i++)
        {
            WHT_IO_Ctrl_Set_Flash_Value((WHT_IO_Ctrl_enum)i, &flash_config);
        }
    }
    else if (name < IO_Ctrl_Sum_Count)
    {
        WHT_IO_Ctrl_Set_Flash_Value(name, &flash_config);
    }

    vTaskResume(WHT_IO_Ctrl_Task_Handle);//恢复任务
}
static void WHT_IO_Ctrl_Start_SOS(WHT_IO_Ctrl_enum name)
{
    if (name == IO_Ctrl_ALL)
    {
        for (unsigned int i = 0; i < IO_Ctrl_Sum_Count; i++)
        {
            WHT_IO_Ctrl_Start_SOS_Config((WHT_IO_Ctrl_enum)i);
        }
    }
    else if (name < IO_Ctrl_Sum_Count)
    {
        WHT_IO_Ctrl_Start_SOS_Config(name);
    }
    
    vTaskResume(WHT_IO_Ctrl_Task_Handle);//恢复任务
}
static void WHT_IO_Ctrl_End_SOS(WHT_IO_Ctrl_enum name)
{
    if (name == IO_Ctrl_ALL)
    {
        for (unsigned int i = 0; i < IO_Ctrl_Sum_Count; i++)
        {
            WHT_IO_Ctrl_End_SOS_Config((WHT_IO_Ctrl_enum)i);
        }
    }
    else if (name < IO_Ctrl_Sum_Count)
    {
        WHT_IO_Ctrl_End_SOS_Config(name);
    }
}
/**************************************外部调用函数********************************************/


static void WHT_IO_Ctrl_Task(void* pvParameters)
{
    TickType_t xLastWakeTime;
    FlagStatus IO_Ctrl_End_Flag;

    xLastWakeTime = xTaskGetTickCount();
    for (; ;)
    {
        IO_Ctrl_End_Flag = SET;
        vTaskDelayUntil(&xLastWakeTime, IO_Ctrl_Task_Update_Rate);//周期性刷新一下for循环
        for (int i = 0; i < IO_Ctrl_Sum_Count; i++)
        {
            switch (WHT_IO_Ctrl_Former[i].Mode)
            {
            case IO_Ctrl_Mode_Switch:   //常亮或常灭
                if (WHT_IO_Ctrl_Former[i].Lock == Unlock)
                {
                    IO_Ctrl_End_Flag = RESET;
                    WHT_IO_Ctrl_Former[i].Lock = Lock;
                    WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, WHT_IO_Ctrl_Former[i].Switch.State);
                }
                break;
            case IO_Ctrl_Mode_Flash:     //闪烁
                if (WHT_IO_Ctrl_Former[i].Lock == Unlock)
                {
                    IO_Ctrl_End_Flag = RESET;
                    WHT_IO_Ctrl_Former[i].Flash.New_Task_Count++;
                    if (WHT_IO_Ctrl_Former[i].Flash.New_Task_Count >= WHT_IO_Ctrl_Former[i].Flash.Cycle_Task_Count)//到达闪烁周期
                    {
                        WHT_IO_Ctrl_Former[i].Flash.New_Task_Count = 0;            //清零
                        if (WHT_IO_Ctrl_Former[i].Flash.Flash_Count == 0)          //一直闪烁
                        {
                            WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_ON);
                        }
                        else if (WHT_IO_Ctrl_Former[i].Flash.Flash_Count == 1)     //闪烁一次
                        {
                            WHT_IO_Ctrl_Former[i].Lock = Lock;
                            WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, WHT_IO_Ctrl_Former[i].Flash.End_State);
                            printf("[WHT_IO_Ctrl]: End %d Flash\r\n", i);            //调试打印
                        }
                        else
                        {
                            WHT_IO_Ctrl_Former[i].Flash.Flash_Count--;
                            WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_ON);
                        }
                    }
                    else if (WHT_IO_Ctrl_Former[i].Flash.New_Task_Count == WHT_IO_Ctrl_Former[i].Flash.ON_Task_Count)
                    {
                        WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_OFF);
                    }   
                    else if (WHT_IO_Ctrl_Former[i].Flash.New_Task_Count == 1)
                    {
                        WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_ON);
                    }
                }
                break;
            case IO_Ctrl_Mode_SOS:       //SOS求救信号
                IO_Ctrl_End_Flag = RESET;
                WHT_IO_Ctrl_Former[i].SOS.New_Task_Count++;
                switch (WHT_IO_Ctrl_Former[i].SOS.Run_State)
                {
                case SOS_Short_Flash: //短闪
                    if (WHT_IO_Ctrl_Former[i].SOS.New_Task_Count >= SOS_Short_Flash_Cycle_Task_Count)//到达短闪周期
                    {
                         WHT_IO_Ctrl_Former[i].SOS.New_Task_Count = 0;                               //清零
                        if (--WHT_IO_Ctrl_Former[i].SOS.Short_Flash_Count == 0)
                        {
                            WHT_IO_Ctrl_Former[i].SOS.Run_State = SOS_Flash_Idle;                    //进入闪烁空闲
                        }
                        else
                        {
                            WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_ON);
                        }
                    }
                    else if (WHT_IO_Ctrl_Former[i].SOS.New_Task_Count == SOS_Short_Flash_ON_Task_Count)
                    {
                        WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_OFF);
                    }
                    else if (WHT_IO_Ctrl_Former[i].SOS.New_Task_Count == 1)
                    {
                        WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_ON);
                    }
                    break;
                case SOS_Length_Flash://长闪
                    if (WHT_IO_Ctrl_Former[i].SOS.New_Task_Count >= SOS_Length_Flash_Cycle_Task_Count)//到达闪烁周期
                    {
                        WHT_IO_Ctrl_Former[i].SOS.New_Task_Count = 0;                                 //清零
                        if (--WHT_IO_Ctrl_Former[i].SOS.Length_Flash_Count == 0)
                        {
                            WHT_IO_Ctrl_Former[i].SOS.Short_Flash_Count = SOS_Flash_Count;           //复位短闪次数
                            WHT_IO_Ctrl_Former[i].SOS.Run_State = SOS_Flash_Idle;                    //进入闪烁空闲
                        }
                        else
                        {
                            WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_ON);
                        }
                    }
                    else if (WHT_IO_Ctrl_Former[i].SOS.New_Task_Count == SOS_Length_Flash_ON_Task_Count)
                    {
                        WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_OFF);
                    }
                    else if (WHT_IO_Ctrl_Former[i].SOS.New_Task_Count == 1)
                    {
                        WHT_IO_Ctrl_Set_Value((WHT_IO_Ctrl_enum)i, IO_Ctrl_ON);
                    }
                    break;
                case SOS_Flash_Idle://闪烁空闲间隔
                    if (WHT_IO_Ctrl_Former[i].SOS.New_Task_Count >= SOS_Flash_Idle_Task_Count)        //到达空闲周期
                    {
                        WHT_IO_Ctrl_Former[i].SOS.New_Task_Count = 0;                                 //清零重新计数
                        if (WHT_IO_Ctrl_Former[i].SOS.Short_Flash_Count)                              //短闪
                        {
                            WHT_IO_Ctrl_Former[i].SOS.Run_State = SOS_Short_Flash;                    //进入SOS_Short_Flash
                        }
                        else if (WHT_IO_Ctrl_Former[i].SOS.Length_Flash_Count)                        //长闪
                        {
                            WHT_IO_Ctrl_Former[i].SOS.Run_State = SOS_Length_Flash;                   //进入SOS_Length_Flash
                        }
                        else
                        {
                            WHT_IO_Ctrl_Former[i].SOS.Run_State = SOS_Cycle_Idle;                     //进入SOS_Cycle_Idle
                        }
                    }
                    break;
                case SOS_Cycle_Idle://周期空闲间隔
                    if (WHT_IO_Ctrl_Former[i].SOS.New_Task_Count >= SOS_Cycle_Idle_Task_Count)        //到达空闲周期
                    {
                        WHT_IO_Ctrl_Former[i].SOS.New_Task_Count = 0;                                 //清零重新计数
                        WHT_IO_Ctrl_Former[i].SOS.Short_Flash_Count = SOS_Flash_Count;                //复位短闪次数
                        WHT_IO_Ctrl_Former[i].SOS.Length_Flash_Count = SOS_Flash_Count;               //复位长闪次数
                        WHT_IO_Ctrl_Former[i].SOS.Run_State = SOS_Short_Flash;                        //进入SOS_Short_Flash
                    }
                    break;
                }
                break;
            }
        }
        if (IO_Ctrl_End_Flag == SET)
        {
            vTaskSuspend(WHT_IO_Ctrl_Task_Handle);
            printf("[WHT_IO_Ctrl]: Suspend\r\n");
        }
    }
}

static void WHT_IO_Ctrl_Install(unsigned char task_priority)
{
    BaseType_t xreturn;

    WHT_IO_Ctrl_State_Reset();
    WHT_IO_Ctrl_Init();

    xreturn = xTaskCreate( WHT_IO_Ctrl_Task, "WHT_IO_Ctrl_Task", 150, NULL, task_priority, &WHT_IO_Ctrl_Task_Handle);
    if (xreturn == pdFAIL)
    {
        printf("WHT:IO_Ctrl Task Create Error!\r\n");
    } 
}
static void WHT_IO_Ctrl_Uninstall(void)
{
    vTaskDelete(WHT_IO_Ctrl_Task_Handle);
    printf("WHT:IO_Ctrl Task Delete OK!\r\n");
}

//IO_Ctrl的控制句柄
const WHT_IO_Ctrl_t WHT_IO_Ctrl = 
{
    .WHT_Install   = WHT_IO_Ctrl_Install,
    .WHT_Uninstall = WHT_IO_Ctrl_Uninstall,
    .WHT_Set_State = WHT_IO_Ctrl_Set_State,
    .WHT_Set_Flash = WHT_IO_Ctrl_Set_Flash,
    .WHT_Start_SOS = WHT_IO_Ctrl_Start_SOS,
    .WHT_End_SOS   = WHT_IO_Ctrl_End_SOS,
};
